#include "TestSelfDebug.h"

#include <cstdio>

#include <sd/SelfDebug.h>

bool func0() {
	defineLocals(int8_t, sInt8, -1, { -1, -2, 3, 4 });
	defineLocals(uint8_t, uInt8, '1', "1234");
	defineLocals(int32_t, sInt32, -1, { -1, -2, 3, 4 });
	defineLocals(uint32_t, uInt32, 1, { 1, 2, 3, 4 });
	if (!sd::SelfDebug::getInstance().infoLocals()) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	return true;
}

inline bool func1() {
	defineLocals(exe::E, e, exe::ONE, { exe::ONE, exe::TWO, exe::THREE, exe::FOUR });
	defineLocals(exe::U, u, { .sInt32_ = -1 }, {{ .sInt32_ = -1 }, { .sInt32_ = -2 }, { .sInt32_ = 3 }, { .sInt32_ = 4 }});
	if (!sd::SelfDebug::getInstance().infoLocals()) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	return true;
}

bool func() {
	printf("[INF] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
	defineLocals(bool, sBool, true, { true, true, true, true });
	defineLocals(signed char, sChr, -1, { -1, -2, 3, 4 });
	defineLocals(unsigned char, uChr, '1', "1234");
	defineLocals(signed int, sInt, -1, { -1, -2, 3, 4 });
	defineLocals(unsigned int, uInt, 1, { 1, 2, 3, 4 });
	defineLocals(float, sFloat, -0.1f, { -0.1f, -0.2f, 0.3f, 0.4f });
	defineLocals(double, sDouble, -0.1d, { -0.1d, -0.2d, 0.3d, 0.4d });
	if (!sd::SelfDebug::getInstance().infoLocals()) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	printf("[INF] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
	if (!func0()) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	printf("[INF] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
	if (!func1()) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	printf("[INF] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
	{
		exe::T<exe::C> t;
		exe::T<exe::C> *tPointer __attribute__((unused)) = &t;
		exe::T<exe::C> &tReference __attribute__((unused)) = t;
		exe::T<exe::C> tArray[2];
		exe::T<exe::C> *tArrayPointer __attribute__((unused)) = tArray;
		exe::T<exe::C> (&tArrayReference)[2] __attribute__((unused)) = tArray;
		exe::T<exe::C> t2dArray[2][2];
		exe::T<exe::C> (*t2dArrayPointer)[2] __attribute__((unused)) = t2dArray;
		exe::T<exe::C> (&t2dArrayReference)[2][2] __attribute__((unused)) = t2dArray;
		exe::T<exe::C> t3dArray[2][2][2];
		exe::T<exe::C> (*t3dArrayPointer)[2][2] __attribute__((unused)) = t3dArray;
		exe::T<exe::C> (&t3dArrayReference)[2][2][2] __attribute__((unused)) = t3dArray;
		if (!sd::SelfDebug::getInstance().infoLocals()) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
	}
	return true;
}

int main(int _argc, char *_argv[]) {
	if (!sd::SelfDebug::getInstance().loadDebugInfo(_argv[0])) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return -1;
	}
	sd::SelfDebug::getInstance().setFlattenMultidimensionalArray(true);
	if (!func()) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return -1;
	}
	return 0;
}
